//
// Created by wyh on 2025-07-23 23:15.
//
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include "serialize/data_stream.h"

using namespace std;
using namespace wyh::serialize;

DataStream::DataStream() : m_pos(0)
{
    m_byteorder = byteOrder();
}

void DataStream::reserve(int len)
{
    int size = m_buf.size();
    int cap = m_buf.capacity();

    if (size + len > cap)
    {
        while (size + len > cap)
        {
            if (cap == 0)
            {
                cap = 1;
            }
            else
            {
                cap *= 2;
            }
        }
        m_buf.reserve(cap);
    }
}

void DataStream::write(const char *data, int len)
{
    reserve(len);
    int size = m_buf.size();
    m_buf.resize(m_buf.size() + len);
    memcpy(&m_buf[size], data, len);

}

void DataStream::write(bool value)
{
    char type = DataType::BOOL;
    write((char *) &type, sizeof(char));
    write((char *) &value, sizeof(char));
}

void DataStream::write(char value)
{
    char type = DataType::CHAR;
    write((char *) &type, sizeof(char));
    write((char *) &value, sizeof(char));
}

void DataStream::write(int32_t value)
{
    char type = DataType::INT32;
    write((char *) &type, sizeof(char));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(int32_t);
        reverse(first, last);
    }
    write((char *) &value, sizeof(int32_t));
}

void DataStream::write(int64_t value)
{
    char type = DataType::INT64;
    write((char *) &type, sizeof(char));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(int64_t);
        reverse(first, last);
    }
    write((char *) &value, sizeof(int64_t));
}

void DataStream::write(float value)
{
    char type = DataType::FLOAT;
    write((char *) &type, sizeof(char));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(float);
        reverse(first, last);
    }
    write((char *) &value, sizeof(float));
}

void DataStream::write(double value)
{
    char type = DataType::DOUBLE;
    write((char *) &type, sizeof(char));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(double);
        reverse(first, last);
    }
    write((char *) &value, sizeof(double));
}

void DataStream::write(const char *value)
{
    char type = DataType::STRING;
    write((char *) &type, sizeof(char));

    int len = strlen(value);
    write(len);
    write(value, len);
}

void DataStream::write(const std::string &value)
{
    write(value.c_str());
}

void DataStream::show() const
{
    int size = m_buf.size();
    cout << "data size = " << size << endl;
    int pos = 0;
    while (pos < size)
    {
        switch ((DataType) m_buf[pos])
        {
            case DataType::BOOL:
            {
                if ((int) m_buf[++pos] == 0)
                {
                    cout << "false";
                }
                else
                {
                    cout << "true";
                }
                ++pos;
                break;
            }
            case DataType::CHAR:
            {
                cout << m_buf[++pos];
                ++pos;
            }
                break;
            case DataType::INT32:
            {
                cout << *((int32_t *) (&m_buf[++pos]));
                pos += sizeof(int32_t);
            }
                break;
            case DataType::INT64:
            {
                cout << *((int64_t *) (&m_buf[++pos]));
                pos += sizeof(int64_t);
            }
                break;
            case DataType::FLOAT:
            {
                cout << *((float *) (&m_buf[++pos]));
                pos += sizeof(float);
            }
                break;
            case DataType::DOUBLE:
            {
                cout << *((double *) (&m_buf[++pos]));
                pos += sizeof(double);
            }
                break;
            case DataType::STRING:
            {
                if ((DataType) m_buf[++pos] == DataType::INT32)
                {
                    int32_t len = *(int32_t *) (&m_buf[++pos]);
                    pos += sizeof(int32_t);
                    cout << string(&m_buf[pos], len);
                    pos += len;
                }
                else
                {
                    throw logic_error("invalid string length");
                }
            }
                break;
            default:
                cout << "invalid data type";
                break;
        }
    }
}

bool DataStream::read(bool &value)
{
    if (m_buf[m_pos] != DataType::BOOL)
    {
        return false;
    }
    ++m_pos;
    value = m_buf[m_pos];
    ++m_pos;
    return true;
}

bool DataStream::read(char &value)
{
    if (m_buf[m_pos] != DataType::CHAR)
    {
        return false;
    }
    ++m_pos;
    value = m_buf[m_pos];
    ++m_pos;
    return true;
    return false;
}

bool DataStream::read(int32_t &value)
{
    if (m_buf[m_pos] != DataType::INT32)
    {
        return false;
    }
    ++m_pos;
    value = *((int32_t *) (&m_buf[m_pos]));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(int32_t);
        reverse(first, last);
    }
    m_pos += sizeof(int32_t);
    return true;
}

bool DataStream::read(int64_t &value)
{
    if (m_buf[m_pos] != DataType::INT64)
    {
        return false;
    }
    ++m_pos;
    value = *((int64_t *) (&m_buf[m_pos]));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(int64_t);
        reverse(first, last);
    }
    m_pos += sizeof(int64_t);
    return true;
}

bool DataStream::read(float &value)
{
    if (m_buf[m_pos] != DataType::FLOAT)
    {
        return false;
    }
    ++m_pos;
    value = *((float *) (&m_buf[m_pos]));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(float);
        reverse(first, last);
    }
    m_pos += sizeof(float);
    return true;
}

bool DataStream::read(double &value)
{
    if (m_buf[m_pos] != DataType::DOUBLE)
    {
        return false;
    }
    ++m_pos;
    value = *((double *) (&m_buf[m_pos]));

    if(m_byteorder==ByteOrder::BigEndian)
    {
        char *first = (char*)&value;
        char *last = first + sizeof(double);
        reverse(first, last);
    }
    m_pos += sizeof(double);
    return true;
}

bool DataStream::read(string &value)
{
    if (m_buf[m_pos] != DataType::STRING)
    {
        return false;
    }
    ++m_pos;
    int len = 0;
    read(len);
    if (len < 0)
    {
        return false;
    }

    value.assign((char*)&(m_buf[m_pos]), len);

    m_pos += len;
    return true;
}

DataStream &DataStream::operator<<(bool value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(char value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(int32_t value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(int64_t value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(float value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(double value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(const char *value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator<<(const string &value)
{
    write(value);
    return *this;
}

DataStream &DataStream::operator>>(bool &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(char &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(int32_t &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(int64_t &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(float &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(double &value)
{
    read(value);
    return *this;
}

DataStream &DataStream::operator>>(string &value)
{
    read(value);
    return *this;
}

bool DataStream::read(char *data, int len)
{
    memcpy(data, (char *) &m_buf[m_pos], len);
    m_pos += len;

    return true;
}

void DataStream::write(const Serializable &value)
{
    value.serialize(*this);
}

DataStream &DataStream::operator<<(const Serializable &value)
{
    write(value);
    return *this;
}

bool DataStream::read(Serializable &value)
{
    return value.unserialize(*this);
}

DataStream &DataStream::operator>>(Serializable &value)
{
    read(value);
    return *this;
}

const char *DataStream::data() const
{
    return m_buf.data();
}

int DataStream::size() const
{
    return m_buf.size();
}

void DataStream::clear()
{
    m_buf.clear();
    m_pos = 0;
}

void DataStream::reset()
{
    m_pos = 0;
}

void DataStream::save(const string &filename)
{
    ofstream ofs(filename);
    ofs.write(data(), size());
    ofs.flush();
    ofs.close();
}

void DataStream::load(const string &filename)
{
    ifstream ifs(filename);
    ostringstream oss;
    oss<<ifs.rdbuf();
    const string &str = oss.str();
    reserve(str.size());
    write(str.data(), str.size());
    ifs.close();
}

DataStream::ByteOrder DataStream::byteOrder()
{
    int n = 0x12345678;
    char str[4];
    memcpy(str, &n, sizeof(int));

    if (str[0] == 0x12)
    {
        return ByteOrder::BigEndian;
    }
    else
    {
        return ByteOrder::LittleEndian;
    }
}





